package br.edu.utfpr.sobjak.java.generics.ex2;

// CLASSES DO MODELO DE DOM�NIO

class Empregado {
	String nome;
	Empregado(String nome) { this.nome = nome; }
}

class Gerente extends Empregado {
	public Gerente(String nome) { super(nome); }
}


// CLASSE UTILIT�RIA GEN�RICA

/**
 * Classe Gen�rica Par.
 * Aceita o tipo Empregado e todos os seus subtipos.
 */
class Par <T extends Empregado> {
	T primeiro;
	T segundo;

	public Par(T a1, T a2) {
		primeiro = a1;
		segundo = a2;
	}
}

// CLASSES DE TESTES DA APLICA��O

public class GenericoEx2 {
	public static void main(String[] args) {
		
		// Instancia��o dos Objetos de dom�nio do problema
		Empregado e1 = new Empregado("Juca");
		Empregado e2 = new Empregado("Tiao");
		Gerente g1 = new Gerente("Z�");
		Gerente g2 = new Gerente("Tuco");
		
		//Instancia��o das classes gen�ricas utilit�rias
		Par<Empregado> par1 = new Par<Empregado>(e1, e2);	//OK! Par de Empregados
		Par<Empregado> par2 = new Par<Empregado>(e1, g1);	//OK! Par de Empregado/Gerente
		Par<Empregado> par3 = new Par<Empregado>(g1, g2); //OK! Par de Gerentes
		Par<Gerente> par4 = new Par<Gerente>(g1, g2); 	//OK! Par de Gerentes
		//ParCoringa<Gerente> par5 = new ParCoringa<Gerente>(e1, e2); //FAIL! Par de Empregados

		
		
		
		
		/* -----------------------------------------------------
		 * CASOS DE TESTES COM CLASSES GEN�RICAS NA APLICA��O
		 * ----------------------------------------------------- */
		
		
		
		//// 1� CASO: Explorando o m�todo Print.printEmpregadoModo1
		
		Print.<Par>printEmpregadoModo1(par1); //OK! Mas apresenta "Unchecked Warwing", pois o par�metros pode ser tanto Par<Empregado>, quanto Par<Gerente>.
		Print.<Par<Empregado>>printEmpregadoModo1(par2); //OK!
		Print.printEmpregadoModo1(par3); //OK, simplificado. Determina que o tipo � Par<Empregado> com base no par�metro passado.
		//Print.printEmpregadoModo1(par4); //Fail! Pois o par�metro � um Par
		Print.<Par>printEmpregadoModo1(par4); //OK! Apesar de par4 ser Par<Gerente> funciona, mas apresenta "Unchecked Warning".
		//Print.<Par<Gerente>>printEmpregadoModo1(par4); //Fail! Pois Par<Gerente> n�o herda do tipo Par<Empregado> gen�rico.
		//Print.<Par<Empregado>>printEmpregadoModo1(par4); //Fail!
		
		
		//// 2� CASO: Explorando o m�todo printEmpregadoModo2
		Print.printEmpregadoModo2(par1);  //OK! Passando um Par<Empregado>
		Print.printEmpregadoModo2(par2);  //OK! Passando um Par<Empregado>
		Print.printEmpregadoModo2(par3);  //OK! Passando um Par<Empregado>
		//Print.printEmpregadoModo2(par4); //Fail! Passando um Par<Gerente>
		
		
		//// 3� CASO: Explorando o m�tofo printGerenteModo1
		// Print.printGerenteModo1(par1);  //Fail! Passando um Par<Empregado>
		Print.printGerenteModo1(par4); //OK! Passando um Par<Gerente>
		
		
		//// 4� CASO: Solu��o para m�todo que aceite tanto "Par<Empregado>", quanto "Par<Gerente>". Uso de Coringas!
		
		Print.printEmpregadoCoringaModo1(par1);  //OK! Passando um "Par<Empregado>". Aceita qualquer tipo gen�rico de Par.
		Print.printEmpregadoCoringaModo1(par4);  //OK! Passando um "Par<Gerente>". Aceita qualquer tipo gen�rico de Par.
		
		Print.printEmpregadoCoringaModo2(par1);  //OK! Passando um "Par<Empregado>". Aceita "Empregado" e seus subtipos.
		Print.printEmpregadoCoringaModo2(par4);  //OK! Passando um "Par<Gerente>". Aceita "Gerente", pois � subtipo de "Empregado".
		
		Print.printEmpregadoCoringaModo3(par1);  //OK! Passando um "Par<Empregado>". Aceita um "Empregado" e seus supertipos.
		//Print.printEmpregadoCoringaModo3(par4);  //Fail! Passando um "Par<Gerente>". Pois "Gerente" n�o � um supertipo de "Empregado".
	}

}

class Print {
	/**
	 * Este m�todo aceita gen�ricos que extendam da classe "Par<Empregado>".
	 * @param a
	 */
	public static <T extends Par<Empregado>> void printEmpregadoModo1(T a) {
		System.out.println("Primeiro: " + a.getClass().getSimpleName() + ": " + a.primeiro.nome);
		System.out.println("Segundo: "  + a.getClass().getSimpleName() + ": " + a.segundo.nome);
		System.out.println();
	}
	
	/**
	 * Este m�todo aceita gen�ricos que extendam da classe "Par<Empregado>".
	 * @param a
	 */
	public static void printEmpregadoModo2(Par<Empregado> a) {
		System.out.println("Primeiro: " + a.getClass().getSimpleName() + ": " + a.primeiro.nome);
		System.out.println("Segundo: "  + a.getClass().getSimpleName() + ": " + a.segundo.nome);
		System.out.println();
	}
	
	/**
	 * Este m�todo aceita gen�ricos que extendam da classe "Par<Gerente>".
	 * @param a
	 */
	public static <T extends Par<Gerente>> void printGerenteModo1(T a) {
		System.out.println("Primeiro: " + a.getClass().getSimpleName() + ": " + a.primeiro.nome);
		System.out.println("Segundo: "  + a.getClass().getSimpleName() + ": " + a.segundo.nome);
		System.out.println();
	}
		
	/**
	 * Aceita um Par gen�rico de qualquer tipo (<?>).
	 * @param a
	 */
	public static void printEmpregadoCoringaModo1(Par<?> a) {
		System.out.println("Primeiro: " + a.getClass().getSimpleName() + ": " + a.primeiro);
		System.out.println("Segundo: "  + a.getClass().getSimpleName() + ": " + a.segundo);
		System.out.println();
	}
	
	/**
	 * Aceita um Par gen�rico de qualquer tipo que extenda de Empregado (Par<? extends Empregado>)
	 * @param a
	 */
	public static void printEmpregadoCoringaModo2(Par<? extends Empregado> a) {
		System.out.println("Primeiro: " + a.getClass().getSimpleName() + ": " + a.primeiro);
		System.out.println("Segundo: "  + a.getClass().getSimpleName() + ": " + a.segundo);
		System.out.println();
	}
		
	/**
	 * Aceita um Par gen�rico de qualquer tipo do qual o Empregado extende (Par<? super Empregado>).
	 * @param a
	 */
	public static void printEmpregadoCoringaModo3(Par<? super Empregado> a) {
		System.out.println("Primeiro: " + a.getClass().getSimpleName() + ": " + a.primeiro);
		System.out.println("Segundo: "  + a.getClass().getSimpleName() + ": " + a.segundo);
		System.out.println();
	}
}

